#include "anatomicaltemplate.h"

AnatomicalTemplate::AnatomicalTemplate(int numberOfROIs)
{
    expectedROIs = numberOfROIs;
	actor = NULL;
	mapper = NULL;
}

AnatomicalTemplate::AnatomicalTemplate()
{
    expectedROIs = 90; //DEFAULT number of regions = 90
	actor = NULL;
	mapper = NULL;
}

int AnatomicalTemplate::getNumberOfROIs()
{
    return expectedROIs;
}

void AnatomicalTemplate::setNumberOfROIs(int n)
{
    expectedROIs = n;

}
AnatomicalRegion *AnatomicalTemplate::getRegion(int i)
{
    return (RegionList.at(i));
}

AnatomicalRegion *AnatomicalTemplate::getRegionById(int id)
{
	for(int i = 0;i<RegionList.size();i++)
		if(RegionList.at(i)->info().RegionID == id)
			return RegionList.at(i);
	return NULL;
}

QVector<AnatomicalRegion*>& AnatomicalTemplate::getRegions() const
{
	return const_cast<QVector<AnatomicalRegion*>&>(RegionList);
}

void AnatomicalTemplate::loadNamesFromFile(std::string filepath)
{
    try
    {
        //16kb buffer, just to be sure
        char buffer[16384];
        std::ifstream file(filepath.c_str());

        while (! file.eof() )
        {
            RegionInfo info;
            file.getline(buffer,16384);
            std::stringstream ss(buffer);
            std::string token(buffer);

            if(token.size()==0)
                continue;

            //skip first token: index
            getline(ss,token,' ');
            //get next token: region id
            getline(ss,token,' ');
            info.RegionID = atoi(token.c_str());
            //get next token: short name
            getline(ss,token,' ');
            info.ShortName = std::string(token);
            getline(ss,token,' ');
            info.LongName = std::string(token);

            //if contains coordinates
            if(getline(ss,token,' '))
                info.CenterX = atof(token.c_str());
            //if contains coordinates
            if(getline(ss,token,' '))
                info.CenterY = atof(token.c_str());
            //if contains coordinates
            if(getline(ss,token,' '))
                info.CenterZ = atof(token.c_str());

            AnatomicalRegion *region = new AnatomicalRegion(info);
            RegionList.push_back(region);

            emit taskUpdate(RegionList.size(),expectedROIs);
        }
        int regsize = RegionList.size();
        if(RegionList.size() != expectedROIs)
            throw "ROI count mismatch";
    }
    catch(std::exception)
    {
        throw tr("An error occured while loading the template region information from the file. Please verify that the file has the correct structure.");
    }
    catch(char*)
    {
        throw tr("An error occured while loading the template region information from the file. The number of regions does not match the size of the correlation matrix.");
    }
}

void AnatomicalTemplate::loadCoordinatesFromFile(std::string filepath)
{
    try
    {
        //16kb buffer, just to be sure
        char buffer[16384];
        std::ifstream file(filepath.c_str());
        int i = 0;
        while (! file.eof() )
        {
            file.getline(buffer,16384);
            std::stringstream ss(buffer);
            std::string line(buffer);
            std::string token;

            if(line.size()==0)
                continue;

            //const RegionInfo& info = ;
            //skip first token: region id
            getline(ss,token,' ');
            //get next token: centerx
            getline(ss,token,' ');
            RegionList.at(i)->info().CenterX = atoi(token.c_str());
            //get next token: centery
            getline(ss,token,' ');
            RegionList.at(i)->info().CenterY = atoi(token.c_str());
            //get next token: centerz
            getline(ss,token,' ');
            RegionList.at(i)->info().CenterZ = atoi(token.c_str());

            emit taskUpdate(i+1,expectedROIs);
            i++;
        }
    }
    catch(std::exception)
    {
        throw tr("BLAAT");
    }
}

int AnatomicalTemplate::getCollectionIndex(int row, int col)
{
    int curIndex = 0;
    for(int i = 0; i < row; i++)
    {
            int itemsThisRow = 89 - i;
            curIndex+=itemsThisRow;
    }
    curIndex+=(col-row-1);
    return curIndex;
}

QPoint AnatomicalTemplate::getMatrixIndex(int index){
	QPoint p;
	int i = (int)(index / 90);
	int j = (index % (90-i)) + i;
	p.setX(i);
	p.setY(j);
	return p;
}

void AnatomicalTemplate::load3DdataFromHdrFile(std::string filepath)
{
        throw tr("Not implemented.");
    /*
	vtkDataSet *data = NULL;
    hdrImageReader::loadDataSetFromFile(filepath,&data);

	createOutlineActor(data);

    for(int i = 0; i < getNumberOfROIs(); i++)
    {
        RegionList.at(i)->extractPolyDataFrom(data);
        emit taskUpdate(i+1,expectedROIs);
    }
	*/
}

void AnatomicalTemplate::createOutlineActor(vtkDataSet *data)
{
	actor = vtkActor::New();
	mapper = vtkPolyDataMapper::New();

	vtkOutlineFilter *outfilt = vtkOutlineFilter::New();
	outfilt->SetInput(data);
	outfilt->Update();
	mapper->SetInput(outfilt->GetOutput());

	actor->SetMapper(mapper);

	outfilt->Delete();
}

void AnatomicalTemplate::load3DdataFromVTIFiles(std::string folderpath)
{
	vtkAppendPolyData *appender = vtkAppendPolyData::New();
	
	int counter = 0;
	//#pragma omp parallel for num_threads(4)
    for(int i = 0; i < getNumberOfROIs(); i++)
    {
		int rId = RegionList.at(counter)->info().RegionID;
		std::stringstream ss;
		std::string fullpath;
		ss << folderpath << "/" << rId << ".vti";
		fullpath = ss.str();
		RegionList.at(counter)->loadPolyDataFromFile(fullpath);
		appender->AddInput(RegionList.at(counter)->getData());
		counter++;
		emit taskUpdate(counter,expectedROIs);
    }

	appender->Update();
	
	vtkPolyData *data = appender->GetOutput();
	createOutlineActor(data);
	
	//data->Delete();
	appender->Delete();
}

void AnatomicalTemplate::attachToRenderer(vtkRenderer *renderer)
{
    for(int i = 0; i < getNumberOfROIs(); i++)
    {
        AnatomicalRegion *reg = getRegion(i);
        reg->attachToRenderer(renderer);
    }
	renderer->AddActor(actor);
}

void AnatomicalTemplate::detachFromRenderer(vtkRenderer *renderer)
{
    for(int i = 0; i < getNumberOfROIs(); i++)
    {
        AnatomicalRegion *reg = getRegion(i);
        reg->detachFromRenderer(renderer);
    }
}

/*void AnatomicalTemplate::setSelection(const QVector<AnatomicalRegion*>& select)
{
    for(int i = 0; i < getNumberOfROIs(); i++)
        getRegion(i)->setVisible(false);

    for(int j = 0; j < select.size(); j++)
        select.at(j)->setVisible(true);
}*/

double* AnatomicalTemplate::getCenterOfLobe(int lobe, BrainHalf half)
{
    double *center = (double*)malloc(sizeof(double)*3);

    double minx= 999999999;
    double miny= 999999999;
    double minz= 999999999;
    double maxx = 0;
    double maxy = 0;
    double maxz = 0;
    int start = 0;
    int step = 2;
    if(half==Right)
        start = 1;
    if(half=Both)
        step=1;

    for(int i = 0; i < getNumberOfROIs(); i+=step)
    {
        double rid = (double)getRegion(i)->info().RegionID;
        int ridpr = (int)floor(rid/1000.0);

        if(lobe != 0 &&
                ridpr != lobe )
                continue;

        RegionInfo rInfo = getRegion(i)->info();
        if(rInfo.CenterX < minx)
                minx = rInfo.CenterX;

        if(rInfo.CenterY < miny)
                miny = rInfo.CenterY;

        if(rInfo.CenterZ < minz)
                minz = rInfo.CenterZ;

        if(rInfo.CenterX > maxx)
                maxx = rInfo.CenterX;

        if(rInfo.CenterY > maxy)
                maxy = rInfo.CenterY;

        if(rInfo.CenterZ > maxz)
                maxz = rInfo.CenterZ;
    }
    center[0] = (maxx + minx) / 2.0;
    center[1] = (maxy + miny) / 2.0;
    center[2] = (maxz + minz) / 2.0;

    return center;
}

vtkActor* AnatomicalTemplate::getOutlineActor()
{
	return actor;
}
